package cn.zhangfusheng.elasticsearch.dynamic;

import cn.zhangfusheng.elasticsearch.annotation.dsl.dynamic.Dynamic;
import cn.zhangfusheng.elasticsearch.annotation.dsl.dynamic.condition.DynamicCondition;
import cn.zhangfusheng.elasticsearch.jexl.Jexl3Analysis;
import cn.zhangfusheng.elasticsearch.jexl.Jexl3Execute;
import cn.zhangfusheng.elasticsearch.jexl.analysis.Analysis;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 动态字符串解析详情
 * @author fusheng.zhang
 * @date 2022-06-20 15:43:12
 */
public class DynamicAnalysisDetail {

    private final Map<String, Object> constantParams;

    private final Map<String, Integer> parameterNames;

    private final List<Analysis> analyses;

    private final Dynamic dynamic;

    private final List<DynamicCondition> dynamicConditions;

    private final Map<DynamicCondition, List<Analysis>> conditionAnalysis;

    public DynamicAnalysisDetail(
            Map<String, Object> constantParams, List<String> parameterNames,
            List<Analysis> analyses, Dynamic dynamic) {
        this.constantParams = constantParams;
        this.analyses = analyses;
        this.dynamic = dynamic;
        this.dynamicConditions = Arrays.asList(dynamic.conditions());
        this.conditionAnalysis =
                this.dynamicConditions.stream().collect(Collectors.toMap(o -> o, o -> new Jexl3Analysis(o.value()).compile()));
        this.parameterNames = new HashMap<>(parameterNames.size());
        for (int i = 0; i < parameterNames.size(); i++) this.parameterNames.put(parameterNames.get(i), i);
    }

    @SuppressWarnings("DuplicatedCode")
    public DyanmicExecuteResult execute(Object[] args) {
        Map<String, Object> params = new HashMap<>(parameterNames.size());
        this.parameterNames.forEach((k, v) -> params.put(k, args[v]));
        StringBuilder result = new StringBuilder();
        List<Object> resultParams = new ArrayList<>(args.length);
        Jexl3Execute jexl3Execute = new Jexl3Execute(params, constantParams);
        this.analyses.forEach(analysis -> analysis.execute(jexl3Execute));
        result.append(jexl3Execute.getResult());
        resultParams.addAll(jexl3Execute.getArgs());

        StringBuilder conditionResult = new StringBuilder();
        boolean appednSplicing = true;
        for (DynamicCondition dynamicCondition : dynamicConditions) {
            Jexl3Execute jexl3Execute_ = new Jexl3Execute(params, constantParams);
            this.conditionAnalysis.get(dynamicCondition).forEach(d -> d.execute(jexl3Execute_));
            String result_ = jexl3Execute_.getResult();
            if (StringUtils.isNotBlank(result_)) {
                if (appednSplicing && dynamicCondition.appendDynamicSplicing() && StringUtils.isNotBlank(dynamic.splicing())) {
                    conditionResult.append(" ").append(dynamic.splicing()).append(" ").append(result_.trim());
                    appednSplicing = false;
                } else {
                    conditionResult.append(" ").append(dynamicCondition.splicing()).append(" ");
                    conditionResult.append(result_.trim());
                }
                resultParams.addAll(jexl3Execute_.getArgs());
            }
        }
        result.append(conditionResult);
        return new DyanmicExecuteResult(dynamic.type(), result, resultParams);
    }
}
